#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <functional>

#include <sys/types.h>
#include <sys/socket.h>

#include "InetAddr.hpp"
#include "ThreadPool.hpp"
using namespace std;

using task_t=function<void()>;//线程池任务处理方式:t()


//MessageRoute类实现将消息转发给所有的客户端
//常规情形下,服务器需要保存用户信息(账号、密码)
//由于客户端发送的消息包含消息内容与套接字信息
//由于InetAddr可以解析每一个客户端的IP地址与Port端口号,可以区分客户端的唯一性

// 服务端获取消息时,需要将客户端插入到在线用户列表vector中---AddUser()
// 某个客户端终止进程时,需要将在线用户列表的具体用户删除---DelUser()

// 服务端获取到的消息转发给所有在线用户---Route()
class MessageRoute
{
private:
    bool IsExist(const InetAddr& user)
    {
        for(auto who:_online_user)
        {
            if(who==user)
            {
                return true;
            }
        }
        return false;
    }
public:
    MessageRoute()
    {}
    void AddUser(const InetAddr& user)
    {
        //首先判断用户是否存在于在线用户列表中
        if(IsExist(user)) return;
        _online_user.push_back(user);
    }
    void DelUser(const InetAddr& user)
    {
        vector<InetAddr>::iterator it=_online_user.begin();
        while(it!=_online_user.end())
        {
            if(*it==user)
            {
                _online_user.erase(it);
                break;
            }
            ++it;
        }
    }

    void RouteHelper(int sockfd,const string message)
    {
        //3. 消息转发(若客户端已退出,将最后的退出消息转发)
        for(auto user:_online_user)
        {
            struct sockaddr_in addr=user.Addr();
            sendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr*)(&addr),sizeof(addr));
        }
    }

    void Route(int sockfd,const string message,const InetAddr who)
    {
        //1. 用户首次发送消息时,不仅需要转发消息,而且需要将用户插入到在线列表中
        AddUser(who);

        //2. 客户端的正常退出方式设置为"Q"/"Quit"
        if(message.c_str()=="Q"|message.c_str()=="Quit")
        {
            DelUser(who);
        }
        //将任务对象放入到线程池的任务队列中
        //将类内成员函数RouteHelper()变成任务对象入队列

        //3.构建任务对象入队列
        function<void()> task=std::bind(&MessageRoute::RouteHelper,this,sockfd,message);
        ThreadPool<task_t>::GetInstance()->Enqueue(task);

        //4.消息转发
    }

    ~MessageRoute()
    {}
private:
   vector<InetAddr> _online_user;

};